/*
 * OpenParts
 * A dynamic-loading components framework for GWT
 * Copyright (C) 2011 Christophe Bouthier  [chris{AT}binary-gastronome{DOT}fr]
 *
 * This work is partially based on work I have done at INRIA (http://www.inria.fr) 
 * in the context of the Qualipso European Project (http://qualipso.org/),
 * The work done at INRIA is Copyright (C) 2006-2011 INRIA
 *
 * This work is distributed under the LGPL version 3
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 3
 * as published by the Free Software Foundation. See the GNU
 * Lesser General Public License in LGPL.txt for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package fr.openparts.OpenParts.test.gwt.tests;

import com.google.gwt.dom.client.Element;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.RootPanel;

import fr.openparts.OpenParts.client.OPBinding;
import fr.openparts.OpenParts.client.OPCommandCallback;
import fr.openparts.OpenParts.client.OPCommandFailureReason;
import fr.openparts.OpenParts.client.OPParams;
import fr.openparts.OpenParts.client.OPPartsLoader;
import fr.openparts.OpenParts.client.OPScheduler;
import fr.openparts.OpenParts.client.OPShell;
import fr.openparts.OpenParts.client.OPSlot;
import fr.openparts.OpenParts.test.gwt.dummyPart.client.DummyPart;

/**
 * GWT tests for the displaying of views of OPShell.
 * 
 * @author Christophe Bouthier [chris{AT}binary-gastronome{DOT}fr]
 * @creation.date 30 December 2009
 */
public class OPShellDisplayViewTestGwt extends GWTTestCase {

    private static final String SERVICE_NAME = "dummyService";
    private static final String RESOURCE_NAME = "dummyResource";
    private static final String ACTION_NAME_1 = "dummyAction1";
    private static final String ACTION_NAME_2 = "dummyAction2";
    private static final String SLOT_ID = "slotId";
    private static final String MANDATORY_PARAM_1 = "dummyParam1";
    private static final String MANDATORY_PARAM_2 = "dummyParam2";

    private static final String VIEW_1_CONTENT = "viewFactorySimple";
    private static final String VIEW_2_CONTENT = "viewFactoryMandatoryParams";

    private DummyPart dummyPart;
    private OPParams params;
    private OPSlot slot;

    private static final int TIMER_TIMEOUT = 5500;
    private static final int TEST_TIMEOUT = 6000;

    private OPCommandCallback callback;
    private Timer timer;

    private int onSuccessCalled = 0;
    private int onFailCalled = 0;
    private OPCommandFailureReason onFailReason;

    /**
     * Return the name of the tested GWT Module.
     * 
     * @see com.google.gwt.junit.client.GWTTestCase#getModuleName()
     */
    @Override
    public final String getModuleName() {
        return "fr.openparts.OpenParts.test.gwt.TestOpenParts";
    }

    /**
     * Called at the start of each test to set up the part.
     * 
     * @see com.google.gwt.junit.client.GWTTestCase#gwtSetUp()
     */
    @Override
    protected void gwtSetUp() throws Exception {
        super.gwtSetUp();
        OPPartsLoader.bind();
        OPScheduler.bind();
        dummyPart = new DummyPart();
        dummyPart.bind();
        params = new OPParams("name", "value");
        slot = OPShell.getSlot(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1);
        callback = new OPCommandCallback() {
            @Override
            public void onSuccess() {
                ++onSuccessCalled;
            }

            @Override
            public void onFail(final OPCommandFailureReason reason) {
                ++onFailCalled;
                onFailReason = reason;
            }
        };
    }

    /**
     * Called at the end of each test to clean up the mess.
     * 
     * @see com.google.gwt.junit.client.GWTTestCase#gwtTearDown()
     */
    @Override
    protected final void gwtTearDown() throws Exception {
        super.gwtTearDown();
        onSuccessCalled = 0;
        onFailCalled = 0;
        onFailReason = null;
        emptyListeners(OPShell.opBindingSharedInstance());
        unbindOPPartsLoader(OPShell.opBindingSharedInstance());
        unbindOPScheduler(OPShell.opBindingSharedInstance());
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
    }

    /**
     * Test getting the service name.
     */
    public final void testGettingServiceName() {
        assertNotNull("Service name shouldn't be null", DummyPart.binder.getServiceName());
        assertEquals("Service name should be dummyService", "dummyService", DummyPart.binder.getServiceName());
    }

    /**
     * Test getting the resources names.
     */
    public final void testGettingResourcesNames() {
        assertNotNull("Array of resources names shouldn't be null", DummyPart.binder.getResourcesNames());
        assertEquals("There should be two resource names", 2, DummyPart.binder.getResourcesNames().length);
        assertEquals("Resource name 1 should be dummyResource1", "dummyResource1", DummyPart.binder.getResourcesNames()[0]);
        assertEquals("Resource name 2 should be dummyResource", "dummyResource", DummyPart.binder.getResourcesNames()[1]);
    }

    /**
     * Test if the given view is binded. Should return true.
     */
    public final void testIsBinded() {
        assertTrue("View 1 should be binded", OPShell.isBinded(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1));
        assertTrue("View 2 should be binded", OPShell.isBinded(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_2));
    }

    /**
     * Test if a given view with null service is binded. Should raise an assertion error.
     */
    public final void testIsBindedWithNullService() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.isBinded(null, RESOURCE_NAME, ACTION_NAME_1);
                fail("OPShell should raise an assertion error when testing if a view with a null service name is binded.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test if a given view with null resource is binded. Should raise an assertion error.
     */
    public final void testIsBindedWithNullResource() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.isBinded(SERVICE_NAME, null, ACTION_NAME_1);
                fail("OPShell should raise an assertion error when testing if a view with a null resource name is binded.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test if a given view with null action is binded. Should raise an assertion error.
     */
    public final void testIsBindedWithNullAction() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.isBinded(SERVICE_NAME, RESOURCE_NAME, null);
                fail("OPShell should raise an assertion error when testing if a view with a null action name is binded.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test if a view with inexistent service is binded. Should return false.
     */
    public final void testIsBindedWithInexistentService() {
        assertFalse("A view with inexistent service should NOT be binded.", OPShell.isBinded("INEXISTENT_SERVICE", RESOURCE_NAME, ACTION_NAME_1));
    }

    /**
     * Test if a view with inexistent resource is binded. Should return false.
     */
    public final void testIsBindedWithInexistentResource() {
        assertFalse("A view with inexistent resource should NOT be binded.", OPShell.isBinded(SERVICE_NAME, "INEXISTENT_RESOURCE", ACTION_NAME_1));
    }

    /**
     * Test if a view with inexistent action is binded. Should return false.
     */
    public final void testIsBindedWithInexistentAction() {
        assertFalse("A view with inexistent action should NOT be binded.", OPShell.isBinded(SERVICE_NAME, RESOURCE_NAME, "INEXISTENT_ACTION"));
    }

    /**
     * Test getting unique slot id. Should get something not null.
     */
    public final void testUniqueSlotId() {
        assertNotNull("Unique slot id shouldn't be null.", OPShell.getUniqueSlotIdFor(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_2));
    }

    /**
     * Test getting an unique slot id 2 times. Should NOT get the same thing each times.
     */
    public final void testUniqueSlotIdTwoTimes() {
        final String uniqueSlotId1 = OPShell.getUniqueSlotIdFor(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_2);
        final String uniqueSlotId2 = OPShell.getUniqueSlotIdFor(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_2);
        assertNotNull("Unique slot id 1 shouldn't be null", uniqueSlotId1);
        assertNotNull("Unique slot id 2 shouldn't be null", uniqueSlotId2);
        assertFalse("Unique slot id shouldn't be the same each time", uniqueSlotId1.equals(uniqueSlotId2));
    }

    /**
     * Test getting unique slot id with null service. Should raise an assertion error.
     */
    public final void testUniqueSlotIdWithNullService() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.getUniqueSlotIdFor(null, RESOURCE_NAME, ACTION_NAME_2);
                fail("OPShell should raise an assertion error when getting an embeddable  slot id with a null service name.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test getting unique slot id with null resource. Should raise an assertion error.
     */
    public final void testUniqueSlotIdWithNullResource() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.getUniqueSlotIdFor(SERVICE_NAME, null, ACTION_NAME_2);
                fail("OPShell should raise an assertion error when getting an embeddable  slot id with a null resource name.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test getting unique slot id with null action. Should raise an assertion error.
     */
    public final void testUniqueSlotIdWithNullAction() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.getUniqueSlotIdFor(SERVICE_NAME, RESOURCE_NAME, null);
                fail("OPShell should raise an assertion error when getting an embeddable  slot id with a null action name.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test getting slot. Should get something not null.
     */
    public final void testSlot() {
        assertNotNull("Slot shouldn't be null.", OPShell.getSlot(SLOT_ID));
    }

    /**
     * Test getting slot with null slot id. Should raise an assertion error.
     */
    public final void testSlotWithNullSlotId() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.getSlot(null);
                fail("OPShell should raise an assertion error when getting a slot with a null slot id.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test getting slot with empty slot id. Should raise an assertion error.
     */
    public final void testSlotWithEmptySlotId() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.getSlot("");
                fail("OPShell should raise an assertion error when getting a slot with an empty slot id.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test getting slot from service, resource, action. Should get something not null.
     */
    public final void testSlotWithServiceResourceAction() {
        assertNotNull("Slot shouldn't be null.", OPShell.getSlot(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_2));
    }

    /**
     * Test getting two slot from service, resource, action. Should NOT get the same thing each times.
     */
    public final void testTwoSlotWithServiceResourceAction() {
        final OPSlot slot1 = OPShell.getSlot(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_2);
        final OPSlot slot2 = OPShell.getSlot(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_2);
        assertNotNull("Slot 1 shouldn't be null", slot1);
        assertNotNull("Slot 2 shouldn't be null", slot2);
        assertNotSame("Slot shouldn't be the same each time", slot1, slot2);
        assertNotSame("Slot id shouldn't be the same each time", slot1.getSlotId(), slot2.getSlotId());
    }

    /**
     * Test getting slot from service, resource, action with null service. Should raise an assertion error.
     */
    public final void testSlotWithServiceResourceActionWithNullService() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.getSlot(null, RESOURCE_NAME, ACTION_NAME_2);
                fail("OPShell should raise an assertion error when getting an embeddable  slot id with a null service name.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test getting slot from service, resource, action with null resource. Should raise an assertion error.
     */
    public final void testSlotWithServiceResourceActionWithNullResource() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.getSlot(SERVICE_NAME, null, ACTION_NAME_2);
                fail("OPShell should raise an assertion error when getting an embeddable  slot id with a null resource name.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test getting slot from service, resource, action with null action. Should raise an assertion error.
     */
    public final void testSlotWithServiceResourceActionWithNullAction() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.getSlot(SERVICE_NAME, RESOURCE_NAME, null);
                fail("OPShell should raise an assertion error when getting an embeddable  slot id with a null action name.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test displaying view with slot id.
     */
    public final void testDisplayViewWithSlotId() {
        RootPanel.getBodyElement().appendChild(OPShell.getSlot(SLOT_ID).getElement());

        assertEquals("simple view should not have been called yet", 0, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should not have been called yet", 0, dummyPart.mandatoryParamsViewFactory);

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1, SLOT_ID);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("simple view should have been called now", 1, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should still not have been called", 0, dummyPart.mandatoryParamsViewFactory);

        final Element slotElement = DOM.getElementById(SLOT_ID);
        assertNotNull("slot element shouldn't be null", slotElement);
        final String viewAsHtml = slotElement.getInnerHTML();
        assertNotNull("view as html shouldn't be null", viewAsHtml);
        assertTrue("view 1 content should be in the page", viewAsHtml.contains(VIEW_1_CONTENT));
    }

    /**
     * Test displaying view with slot id with params.
     */
    public final void testDisplayViewWithSlotIdWithParams() {
        RootPanel.getBodyElement().appendChild(OPShell.getSlot(SLOT_ID + "1").getElement());

        assertEquals("simple view should not have been called yet", 0, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should not have been called yet", 0, dummyPart.mandatoryParamsViewFactory);

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1, SLOT_ID + "1", params);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("simple view should have been called now", 1, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should still not have been called", 0, dummyPart.mandatoryParamsViewFactory);

        final Element slotElement = DOM.getElementById(SLOT_ID + "1");
        assertNotNull("slot element shouldn't be null", slotElement);
        final String viewAsHtml = slotElement.getInnerHTML();
        assertNotNull("view as html shouldn't be null", viewAsHtml);
        assertTrue("view 1 content should be in the page", viewAsHtml.contains(VIEW_1_CONTENT));
    }

    /**
     * Test displaying view with slot id with callback.
     */
    public final void testDisplayViewWithSlotIdWithCallback() {
        RootPanel.getBodyElement().appendChild(OPShell.getSlot(SLOT_ID + "2").getElement());

        assertEquals("simple view should not have been called yet", 0, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should not have been called yet", 0, dummyPart.mandatoryParamsViewFactory);

        assertEquals("onSuccess should not have been called yet", 0, onSuccessCalled);
        assertEquals("onFail should not have been called yet", 0, onFailCalled);

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1, SLOT_ID + "2", callback);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("simple view should have been called now", 1, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should still not have been called", 0, dummyPart.mandatoryParamsViewFactory);

        assertEquals("onSuccess should have been called now", 1, onSuccessCalled);
        assertEquals("onFail should still not have been called", 0, onFailCalled);

        final Element slotElement = DOM.getElementById(SLOT_ID + "2");
        assertNotNull("slot element shouldn't be null", slotElement);
        final String viewAsHtml = slotElement.getInnerHTML();
        assertNotNull("view as html shouldn't be null", viewAsHtml);
        assertTrue("view 1 content should be in the page", viewAsHtml.contains(VIEW_1_CONTENT));
    }

    /**
     * Test displaying view with slot id with params and callback.
     */
    public final void testDisplayViewWithSlotIdWithParamsAndCallback() {
        RootPanel.getBodyElement().appendChild(OPShell.getSlot(SLOT_ID + "3").getElement());

        assertEquals("simple view should not have been called yet", 0, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should not have been called yet", 0, dummyPart.mandatoryParamsViewFactory);

        assertEquals("onSuccess should not have been called yet", 0, onSuccessCalled);
        assertEquals("onFail should not have been called yet", 0, onFailCalled);

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1, SLOT_ID + "3", params, callback);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("simple view should have been called now", 1, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should still not have been called", 0, dummyPart.mandatoryParamsViewFactory);

        assertEquals("onSuccess should have been called now", 1, onSuccessCalled);
        assertEquals("onFail should still not have been called", 0, onFailCalled);

        final Element slotElement = DOM.getElementById(SLOT_ID + "3");
        assertNotNull("slot element shouldn't be null", slotElement);
        final String viewAsHtml = slotElement.getInnerHTML();
        assertNotNull("view as html shouldn't be null", viewAsHtml);
        assertTrue("view 1 content should be in the page", viewAsHtml.contains(VIEW_1_CONTENT));
    }

    /**
     * Test displaying view with slot.
     */
    public final void testDisplayViewWithSlot() {
        RootPanel.getBodyElement().appendChild(slot.getElement());

        assertEquals("simple view should not have been called yet", 0, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should not have been called yet", 0, dummyPart.mandatoryParamsViewFactory);

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1, slot);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("simple view should have been called now", 1, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should still not have been called", 0, dummyPart.mandatoryParamsViewFactory);

        final Element slotElement = DOM.getElementById(slot.getSlotId());
        assertNotNull("slot element shouldn't be null", slotElement);
        final String viewAsHtml = slotElement.getInnerHTML();
        assertNotNull("view as html shouldn't be null", viewAsHtml);
        assertTrue("view 1 content should be in the page", viewAsHtml.contains(VIEW_1_CONTENT));
    }

    /**
     * Test displaying view with slot with params.
     */
    public final void testDisplayViewWithSlotWithParams() {
        RootPanel.getBodyElement().appendChild(slot.getElement());

        assertEquals("simple view should not have been called yet", 0, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should not have been called yet", 0, dummyPart.mandatoryParamsViewFactory);

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1, slot, params);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("simple view should have been called now", 1, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should still not have been called", 0, dummyPart.mandatoryParamsViewFactory);

        final Element slotElement = DOM.getElementById(slot.getSlotId());
        assertNotNull("slot element shouldn't be null", slotElement);
        final String viewAsHtml = slotElement.getInnerHTML();
        assertNotNull("view as html shouldn't be null", viewAsHtml);
        assertTrue("view 1 content should be in the page", viewAsHtml.contains(VIEW_1_CONTENT));
    }

    /**
     * Test displaying view with slot with callback.
     */
    public final void testDisplayViewWithSlotWithCallback() {
        RootPanel.getBodyElement().appendChild(slot.getElement());

        assertEquals("simple view should not have been called yet", 0, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should not have been called yet", 0, dummyPart.mandatoryParamsViewFactory);

        assertEquals("onSuccess should not have been called yet", 0, onSuccessCalled);
        assertEquals("onFail should not have been called yet", 0, onFailCalled);

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1, slot, callback);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("simple view should have been called now", 1, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should still not have been called", 0, dummyPart.mandatoryParamsViewFactory);

        assertEquals("onSuccess should have been called now", 1, onSuccessCalled);
        assertEquals("onFail should still not have been called", 0, onFailCalled);

        final Element slotElement = DOM.getElementById(slot.getSlotId());
        assertNotNull("slot element shouldn't be null", slotElement);
        final String viewAsHtml = slotElement.getInnerHTML();
        assertNotNull("view as html shouldn't be null", viewAsHtml);
        assertTrue("view 1 content should be in the page", viewAsHtml.contains(VIEW_1_CONTENT));
    }

    /**
     * Test displaying view with slot with params and callback.
     */
    public final void testDisplayViewWithSlotWithParamsAndCallback() {
        RootPanel.getBodyElement().appendChild(slot.getElement());

        assertEquals("simple view should not have been called yet", 0, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should not have been called yet", 0, dummyPart.mandatoryParamsViewFactory);

        assertEquals("onSuccess should not have been called yet", 0, onSuccessCalled);
        assertEquals("onFail should not have been called yet", 0, onFailCalled);

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1, slot, params, callback);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("simple view should have been called now", 1, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should still not have been called", 0, dummyPart.mandatoryParamsViewFactory);

        assertEquals("onSuccess should have been called now", 1, onSuccessCalled);
        assertEquals("onFail should still not have been called", 0, onFailCalled);

        final Element slotElement = DOM.getElementById(slot.getSlotId());
        assertNotNull("slot element shouldn't be null", slotElement);
        final String viewAsHtml = slotElement.getInnerHTML();
        assertNotNull("view as html shouldn't be null", viewAsHtml);
        assertTrue("view 1 content should be in the page", viewAsHtml.contains(VIEW_1_CONTENT));
    }

    /**
     * Test trying to display view with service loading failure.
     */
    public final void testDisplayViewWithServiceLoadingFailure() {
        RootPanel.getBodyElement().appendChild(slot.getElement());

        assertEquals("onSuccess should not have been called yet", 0, onSuccessCalled);
        assertEquals("onFail should not have been called yet", 0, onFailCalled);

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1, slot, params, callback);

        timer = new Timer() {
            public void run() {
                assertEquals("onSuccess should still not have been called", 0, onSuccessCalled);
                assertEquals("onFail should have been called now", 1, onFailCalled);
                assertNotNull("reason shouldn't be null", onFailReason);
                assertEquals("reason should be pre command failed", OPCommandFailureReason.TYPE_PRE_COMMAND_FAILED, onFailReason.getType());
                assertNotNull("reason params shouldn't be null", onFailReason.getParams());
                assertEquals("reason service should be " + SERVICE_NAME, SERVICE_NAME,
                        onFailReason.getParams().getParamValue(OPCommandFailureReason.PARAM_SERVICE));
                finishTest();
            }
        };

        timer.schedule(TIMER_TIMEOUT);
        delayTestFinish(TEST_TIMEOUT);
    }

    /**
     * Test trying to display view with invalid service.
     */
    public final void testDisplayViewWithInvalidService() {
        RootPanel.getBodyElement().appendChild(slot.getElement());

        assertEquals("onSuccess should not have been called yet", 0, onSuccessCalled);
        assertEquals("onFail should not have been called yet", 0, onFailCalled);

        OPShell.displayView("INVALID_SERVICE", RESOURCE_NAME, ACTION_NAME_1, slot, callback);
        OPShell.notifyLoadingCompleted("INVALID_SERVICE");

        assertEquals("onSuccess should still not have been called", 0, onSuccessCalled);
        assertEquals("onFail should have been called now", 1, onFailCalled);
        assertNotNull("reason shouldn't be null", onFailReason);
        assertEquals("reason should be no such view", OPCommandFailureReason.TYPE_NO_SUCH_VIEW, onFailReason.getType());
        assertNotNull("reason params shouldn't be null", onFailReason.getParams());
        assertEquals("reason service should be " + "INVALID_SERVICE", "INVALID_SERVICE",
                onFailReason.getParams().getParamValue(OPCommandFailureReason.PARAM_SERVICE));
        assertEquals("reason resource should be " + RESOURCE_NAME, RESOURCE_NAME, onFailReason.getParams().getParamValue(OPCommandFailureReason.PARAM_RESOURCE));
        assertEquals("reason action should be " + ACTION_NAME_1, ACTION_NAME_1, onFailReason.getParams().getParamValue(OPCommandFailureReason.PARAM_ACTION));
    }

    /**
     * Test trying to display view with invalid resource.
     */
    public final void testDisplayViewWithInvalidResource() {
        RootPanel.getBodyElement().appendChild(slot.getElement());

        assertEquals("onSuccess should not have been called yet", 0, onSuccessCalled);
        assertEquals("onFail should not have been called yet", 0, onFailCalled);

        OPShell.displayView(SERVICE_NAME, "INVALID_RESOURCE", ACTION_NAME_1, slot, callback);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("onSuccess should still not have been called", 0, onSuccessCalled);
        assertEquals("onFail should have been called now", 1, onFailCalled);
        assertNotNull("reason shouldn't be null", onFailReason);
        assertEquals("reason should be no such view", OPCommandFailureReason.TYPE_NO_SUCH_VIEW, onFailReason.getType());
        assertNotNull("reason params shouldn't be null", onFailReason.getParams());
        assertEquals("reason service should be " + SERVICE_NAME, SERVICE_NAME, onFailReason.getParams().getParamValue(OPCommandFailureReason.PARAM_SERVICE));
        assertEquals("reason resource should be " + "INVALID_RESOURCE", "INVALID_RESOURCE",
                onFailReason.getParams().getParamValue(OPCommandFailureReason.PARAM_RESOURCE));
        assertEquals("reason action should be " + ACTION_NAME_1, ACTION_NAME_1, onFailReason.getParams().getParamValue(OPCommandFailureReason.PARAM_ACTION));
    }

    /**
     * Test trying to display view with invalid action.
     */
    public final void testDisplayViewWithInvalidAction() {
        RootPanel.getBodyElement().appendChild(slot.getElement());

        assertEquals("onSuccess should not have been called yet", 0, onSuccessCalled);
        assertEquals("onFail should not have been called yet", 0, onFailCalled);

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, "INVALID_ACTION", slot, callback);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("onSuccess should still not have been called", 0, onSuccessCalled);
        assertEquals("onFail should have been called now", 1, onFailCalled);
        assertNotNull("reason shouldn't be null", onFailReason);
        assertEquals("reason should be no such view", OPCommandFailureReason.TYPE_NO_SUCH_VIEW, onFailReason.getType());
        assertNotNull("reason params shouldn't be null", onFailReason.getParams());
        assertEquals("reason service should be " + SERVICE_NAME, SERVICE_NAME, onFailReason.getParams().getParamValue(OPCommandFailureReason.PARAM_SERVICE));
        assertEquals("reason resource should be " + RESOURCE_NAME, RESOURCE_NAME, onFailReason.getParams().getParamValue(OPCommandFailureReason.PARAM_RESOURCE));
        assertEquals("reason action should be " + "INVALID_ACTION", "INVALID_ACTION",
                onFailReason.getParams().getParamValue(OPCommandFailureReason.PARAM_ACTION));
    }

    /**
     * Test displaying view with inexistent slot id. Should raise an assertion error.
     */
    public final void testDisplayViewWithInexistentSlotId() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1, SLOT_ID + "4");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test displaying view with null service. Should raise an assertion error.
     */
    public final void testDisplayViewWithNullService() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.displayView(null, RESOURCE_NAME, ACTION_NAME_1, slot);
                fail("OPShell should raise an assertion error when displaying a view with a null service name.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test displaying view with null resource. Should raise an assertion error.
     */
    public final void testDisplayViewWithNullResource() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.displayView(SERVICE_NAME, null, ACTION_NAME_1, slot);
                fail("OPShell should raise an assertion error when displaying a view with a null resource name.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test displaying view with null action. Should raise an assertion error.
     */
    public final void testDisplayViewWithNullAction() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, null, slot);
                fail("OPShell should raise an assertion error when displaying a view with a null action name.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test displaying view with null slot id. Should raise an assertion error.
     */
    public final void testDisplayViewWithNullSlotId() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1, (String) null);
                fail("OPShell should raise an assertion error when displaying a view with a null slot id.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test displaying view with empty slot id. Should raise an assertion error.
     */
    public final void testDisplayViewWithEmptySlotId() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1, "");
                fail("OPShell should raise an assertion error when displaying a view with an empty slot id.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test displaying view with null slot. Should raise an assertion error.
     */
    public final void testDisplayViewWithNullSlot() {
        if (assertionsAreEnabled()) {
            try {
                OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1, (OPSlot) null);
                fail("OPShell should raise an assertion error when displaying a view with a null slot.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test displaying view as root.
     */
    public final void testDisplayViewAsRoot() {
        assertEquals("simple view should not have been called yet", 0, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should not have been called yet", 0, dummyPart.mandatoryParamsViewFactory);

        assertEquals("onSuccess should not have been called yet", 0, onSuccessCalled);
        assertEquals("onFail should not have been called yet", 0, onFailCalled);

        OPShell.displayViewAsRoot(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_1, params, callback);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("simple view should have been called now", 1, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should still not have been called", 0, dummyPart.mandatoryParamsViewFactory);

        assertEquals("onSuccess should have been called now", 1, onSuccessCalled);
        assertEquals("onFail should still not have been called", 0, onFailCalled);

        final String viewAsHtml = RootPanel.getBodyElement().getInnerHTML();
        assertNotNull("view as html shouldn't be null", viewAsHtml);
        assertTrue("view 1 content is in the page", viewAsHtml.contains(VIEW_1_CONTENT));
    }

    /**
     * Test displaying view with mandatory params.
     */
    public final void testDisplayViewWithMandatoryParams() {
        final OPParams mandatoryParams = new OPParams(MANDATORY_PARAM_1, "dummyValue1", MANDATORY_PARAM_2, "dummyValue2");
        RootPanel.getBodyElement().appendChild(slot.getElement());

        assertEquals("simple view should not have been called yet", 0, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should not have been called yet", 0, dummyPart.mandatoryParamsViewFactory);

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_2, slot, mandatoryParams);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("simple view should still not have been called", 0, dummyPart.simpleViewFactory);
        assertEquals("mandatory params view should have been called now", 1, dummyPart.mandatoryParamsViewFactory);

        final Element slotElement = DOM.getElementById(slot.getSlotId());
        assertNotNull("slot element shouldn't be null", slotElement);
        final String viewAsHtml = slotElement.getInnerHTML();
        assertNotNull("view as html shouldn't be null", viewAsHtml);
        assertTrue("view 2 content is in the page", viewAsHtml.contains(VIEW_2_CONTENT));
    }

    /**
     * Test displaying view with missing mandatory params. Should call onFail callback with missing mandatory param reason.
     */
    public final void testDisplayViewWithMissingMandatoryParams() {
        RootPanel.getBodyElement().appendChild(slot.getElement());

        assertEquals("onSuccess should not have been called yet", 0, onSuccessCalled);
        assertEquals("onFail should not have been called yet", 0, onFailCalled);

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_2, slot, callback);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("onSuccess should still not have been called", 0, onSuccessCalled);
        assertEquals("onFail should have been called now", 1, onFailCalled);
        assertNotNull("reason shouldn't be null", onFailReason);
        assertEquals("reason should be missing mandatory param", OPCommandFailureReason.TYPE_MISSING_MANDATORY_PARAMS, onFailReason.getType());
        assertNotNull("reason params shouldn't be null", onFailReason.getParams());
        assertEquals("reason missing param should be " + MANDATORY_PARAM_1, MANDATORY_PARAM_1,
                onFailReason.getParams().getParamValue(OPCommandFailureReason.PARAM_MISSING_PARAM));
    }

    /**
     * Test displaying view with another missing mandatory params. Should call onFail callback with missing mandatory param reason.
     */
    public final void testDisplayViewWithAnotherMissingMandatoryParams() {
        RootPanel.getBodyElement().appendChild(slot.getElement());

        assertEquals("onSuccess should not have been called yet", 0, onSuccessCalled);
        assertEquals("onFail should not have been called yet", 0, onFailCalled);

        OPShell.displayView(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME_2, slot, new OPParams(MANDATORY_PARAM_1, "value1"), callback);
        OPShell.notifyLoadingCompleted(SERVICE_NAME);

        assertEquals("onSuccess should still not have been called", 0, onSuccessCalled);
        assertEquals("onFail should have been called now", 1, onFailCalled);
        assertNotNull("reason shouldn't be null", onFailReason);
        assertEquals("reason should be missing mandatory param", OPCommandFailureReason.TYPE_MISSING_MANDATORY_PARAMS, onFailReason.getType());
        assertNotNull("reason params shouldn't be null", onFailReason.getParams());
        assertEquals("reason missing param should be " + MANDATORY_PARAM_2, MANDATORY_PARAM_2,
                onFailReason.getParams().getParamValue(OPCommandFailureReason.PARAM_MISSING_PARAM));
    }

    /**
     * Unbind the OPScheduler.
     */
    private final native void unbindOPScheduler(final OPBinding opbinding) /*-{
        opbinding.scheduler = null;
    }-*/;

    /**
     * Unbind the OPPartsLoader.
     */
    private final native void unbindOPPartsLoader(final OPBinding binding) /*-{
        binding.partsLoader = null;
    }-*/;

    /**
     * Native helper method to clean up event bus listener.
     */
    private final native void emptyListeners(final OPBinding binding) /*-{
        binding.listeners = {};
    }-*/;

    /**
     * Check if assertions are enabled.
     * 
     * @return true if assertions are enabled, false otherwise
     */
    private final boolean assertionsAreEnabled() {
        try {
            assert false;
            return false;
        } catch (AssertionError e) {
            return true;
        }
    }
}
